package com.wawei.seeds.me;

import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.widget.SwipeRefreshLayout;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.HeaderViewListAdapter;
import android.widget.TextView;

import com.wawei.seeds.R;
import com.wawei.seeds.adapter.SeedsBaseAdapter;
import com.wawei.seeds.model.WalnutMainEvent;
import com.wawei.seeds.services.ServiceHandler;
import com.wawei.seeds.utils.PullupToMoreListView;
import com.wawei.seeds.utils.RetrofitNetworkService;
import com.wawei.seeds.utils.WalnutBaseNofityHandler;
import com.wawei.seeds.utils.WalnutNotifyHandler;

import java.util.List;

import butterknife.ButterKnife;
import butterknife.InjectView;
import butterknife.Optional;
import retrofit.RestAdapter;

/**
 * A abstract class for processing the common logic such as setting "back" function and "title", and
 * hiding the logic of injection initialization.
 *
 * Created by t27891 on 15/6/21.
 */
public abstract class MeBaseFragment extends Fragment {
    @InjectView(R.id.walnut_me_back)View backView;
    @InjectView(R.id.walnut_me_title)TextView titleView;
    @Optional @InjectView(R.id.walnut_me_pull_refresh)SwipeRefreshLayout refreshLayout;
    @Optional @InjectView(R.id.walnut_me_list)PullupToMoreListView moreListView;
    @Optional @InjectView(R.id.walnut_me_progress)View progressView;

    /**
     * Data adapter for ME
     */
    private SeedsBaseAdapter<WalnutMainEvent> myDataAdapter;
    /**
     * remote data async operation handler
     */
    private WalnutMeNotifyHandler notifyHandler;

    private boolean usingDefault = false;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = onCreateViewBeforeInjection(inflater, container, savedInstanceState);
        if(null == view){//Using default ME layout view
            view = inflater.inflate(R.layout.fragment_walnut_me, container, false);
            usingDefault = true;
        }
        ButterKnife.inject(this, view);
        onCreateViewAfterInjection(view, inflater, container, savedInstanceState);
        return view;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        backView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                switchFragment(MeMainActivity.HOME);
            }
        });
        if(usingDefault) {
            refreshLayout.setColorSchemeResources(R.color.swipe_color_1
                    , R.color.swipe_color_2
                    , R.color.swipe_color_3
                    , R.color.swipe_color_4);
            refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
                @Override
                public void onRefresh() {
                    if (!refreshLayout.isRefreshing()) {
                        refreshLayout.setRefreshing(true);
                    }
                    refreshMyNewData();
                }
            });

            moreListView.setOnLoadMoreListener(new PullupToMoreListView.OnLoadMoreListener() {
                @Override
                public void onLoadMore() {
                    refreshMyOldData();
                }
            });

            moreListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    itemClicked(parent, view, position, id, moreListView.getItemAtPosition(position));
                }
            });

            notifyHandler = new WalnutMeNotifyHandler(this);
            initMyData();
        }
        titleView.setText(getTitle());
        onViewCreatedAfterTitle(view, savedInstanceState);
    }

    private void itemClicked(AdapterView<?> parent, View view, int position, long id, Object data){
        Intent itemIntent = makeIntent4ListItemClicked(parent, view, position, id, data);
        if(null != itemIntent) {
            getActivity().startActivity(itemIntent);
        }
    }

    /**
     * Initialize the list data
     */
    private void initMyData(){
        RestAdapter adapter = RetrofitNetworkService.makeAsyncRestAdapter();
        makeServiceHandler().retrieveData(adapter, makeConditionBundle(WalnutNotifyHandler.INIT_ACHIEVE_DATA),
                notifyHandler, WalnutNotifyHandler.INIT_ACHIEVE_DATA);
    }

    /**
     * Retrieve the latest data from remote server
     */
    private void refreshMyNewData(){
        RestAdapter adapter = RetrofitNetworkService.makeAsyncRestAdapter();
        makeServiceHandler().retrieveData(adapter,makeConditionBundle(WalnutNotifyHandler.LOAD_NEW_ACHIEVE_DATA),
                notifyHandler, WalnutNotifyHandler.LOAD_NEW_ACHIEVE_DATA);
    }

    /**
     *Retrieve the last data from remote server
     */
    private void refreshMyOldData(){
        RestAdapter adapter = RetrofitNetworkService.makeAsyncRestAdapter();
        makeServiceHandler().retrieveData(adapter,makeConditionBundle(WalnutNotifyHandler.LOAD_OLD_ACHIEVE_DATA),
                notifyHandler, WalnutNotifyHandler.LOAD_OLD_ACHIEVE_DATA);
    }

    /**
     * Async notify handler for ME's remote data operation
     */
    protected static class WalnutMeNotifyHandler
            extends WalnutBaseNofityHandler<MeBaseFragment, WalnutMainEvent> {

        private HeaderViewListAdapter headerAdapter;
        public WalnutMeNotifyHandler(MeBaseFragment walnutMainActivity) {
            super(walnutMainActivity);
        }

        @Override
        public void doInitData(MeBaseFragment o, List<WalnutMainEvent> data) {
            get().myDataAdapter = get().makeListAdapter();
            get().myDataAdapter.setDataset(data);

            if(null != get().moreListView){
                get().moreListView.setAdapter(get().myDataAdapter);
            }
            get().refreshLayout.setRefreshing(false);
            if(get().progressView.getVisibility() == View.VISIBLE){
                get().progressView.setVisibility(View.GONE);
            }
        }

        @Override
        public void doNewData(MeBaseFragment o, List<WalnutMainEvent> data) {
            headerAdapter =
                    (HeaderViewListAdapter)get().moreListView.getAdapter();
            SeedsBaseAdapter mAdapter = (SeedsBaseAdapter)headerAdapter.getWrappedAdapter();
            mAdapter.insertDataset(data);
            mAdapter.notifyDataSetChanged();

            get().refreshLayout.setRefreshing(false);
        }

        @Override
        public void doOldData(MeBaseFragment o, List<WalnutMainEvent> data) {
            headerAdapter =
                    (HeaderViewListAdapter)get().moreListView.getAdapter();
            SeedsBaseAdapter mAdapter = (SeedsBaseAdapter)headerAdapter.getWrappedAdapter();
            mAdapter.appendDataset(data);
            mAdapter.notifyDataSetChanged();

            get().moreListView.onLoadMoreComplete();
        }
    }

    /**
     * switch fragments attached on the main activity (MeMainActivity)
     * @param tag   fragment tag
     */
    private void switchFragment(int tag){
        ((MeMainActivity)getActivity()).onSelectFragment(tag);
    }

    /********************************************************************************************
     *
     *                                      Abstracts
     *
     *******************************************************************************************/

    /**
     * Callback method to be invoked when an item in this AdapterView has
     * been clicked.
     * <p>
     * Implementers can call getItemAtPosition(position) if they need
     * to access the data associated with the selected item.
     *
     * @param parent The AdapterView where the click happened.
     * @param view The view within the AdapterView that was clicked (this
     *            will be a view provided by the adapter)
     * @param position The position of the view in the adapter.
     * @param id The row id of the item that was clicked.
     * @param itemData The data bound with the selected item
     */
    public abstract Intent makeIntent4ListItemClicked(AdapterView<?> parent, View view,
                                                      int position, long id, Object itemData);

    /**
     * Make the condition bundle for service handler
     * @param phase the phase of processing data
     * @return condition bundle
     */
    public abstract Bundle makeConditionBundle(int phase);

    /**
     * Make the data adapter for list view. The result type must be WalnutMainActivityAdapter.WalnutMainEvent
     * @return
     */
    public abstract SeedsBaseAdapter<WalnutMainEvent> makeListAdapter();

    /**
     * Make the service handler for remote async calling
     * @return
     */
    public abstract ServiceHandler makeServiceHandler();

    /**
     * Inflate the layout view of the fragment before injection of ButterKnife
     *
     * @param inflater  layout inflater of the fragment
     * @param container container of the fragment view
     * @param savedInstanceState savedInstanceState
     * @return  the view presents the fragment real display
     */
    public abstract View onCreateViewBeforeInjection(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState);

    /**
     * There maybe more work about processing view to do after the injection
     * It's a hook for doing more view works.
     *
     * @param view      the inflated view
     * @param inflater  layout inflater of the fragment
     * @param container container of the fragment view
     * @param savedInstanceState    saved instance state
     */
    public abstract void onCreateViewAfterInjection(View view, LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState);

    /**
     * There maybe more work about processing view object to do after setting the title of fragment.
     * It's a hook for doing that.
     *
     * @param view the inflated view
     * @param savedInstanceState    saved instance state
     */
    public abstract void onViewCreatedAfterTitle(View view, Bundle savedInstanceState);

    /**
     * retrieve the title of fragment
     * @return  the title of fragment
     */
    public abstract String getTitle();
}
